﻿
Imports std
Imports centrosphere
Imports centrosphere.job.storage
Imports command = centrosphere.job.storage.command
Imports update_key_mappings_switcher = switcher(Of Byte, std.pair(Of centrosphere.indexedJob, System.UInt32), Byte)

Partial Public Class storageJobRandomDistributor
    Inherits storageJobDistributor

    Private Shared ReadOnly find_key_hash_commands() As command = {command.write,
                                                                   command.uniqueWrite,
                                                                   command.modify}
    Private Shared ReadOnly find_key_fail_commands() As command = {command.delete,
                                                                   command.read,
                                                                   command.seek,
                                                                   command.sizeof}
    Private Shared ReadOnly buff_merge_commands() As command = {command.read}
    Private Shared ReadOnly i64_sum_commands() As command = {command.capacity,
                                                             command.valuesize,
                                                             command.status,
                                                             command.sizeof,
                                                             command.keycount}
    Private Shared ReadOnly vs_intersect_commands() As command = {command.list}
    Private ReadOnly distributors As storageJob_distribute_switcher = Nothing
    Private ReadOnly aggregators As storageJob_aggregate_switcher = Nothing
    Private ReadOnly update_key_mappings As update_key_mappings_switcher = Nothing
    Private ReadOnly key_mappings As vector(Of key_mapping) = Nothing

    Private Shared Function distribute_condition(ByVal cmd As Byte,
                                                 ByVal action As distribute_delegate) _
                                                As storageJob_distribute_switcher.condition_action
        Return New storageJob_distribute_switcher.condition_action(cmd, action)
    End Function

    Private Shared Function aggregate_condition(ByVal cmd As Byte,
                                                ByVal action As aggregate_delegate) _
                                               As storageJob_aggregate_switcher.condition_action
        Return New storageJob_aggregate_switcher.condition_action(cmd, action)
    End Function

    Public Sub New()
        key_mappings = New vector(Of key_mapping)()

        Dim ds As vector(Of storageJob_distribute_switcher.condition_action) = Nothing
        Dim [as] As vector(Of storageJob_aggregate_switcher.condition_action) = Nothing
        Dim ks As vector(Of update_key_mappings_switcher.condition_action) = Nothing
        ds = New vector(Of storageJob_distribute_switcher.condition_action)()
        [as] = New vector(Of storageJob_aggregate_switcher.condition_action)()
        ks = New vector(Of update_key_mappings_switcher.condition_action)()
        For i As Byte = job.firstOfStorage To command.last - 1
            If find_key_hash_commands.has(i) Then
                ds.push_back(distribute_condition(i, AddressOf find_key_hash_distribute))
            ElseIf find_key_fail_commands.has(i) Then
                ds.push_back(distribute_condition(i, AddressOf find_key_fail_distribute))
            Else
                ds.push_back(distribute_condition(i, AddressOf spread_distribute))
            End If

            If buff_merge_commands.has(i) Then
                [as].push_back(aggregate_condition(i, AddressOf buff_merge_aggregate))
            ElseIf i64_sum_commands.has(i) Then
                [as].push_back(aggregate_condition(i, AddressOf i64_sum_aggregate))
            ElseIf vs_intersect_commands.has(i) Then
                [as].push_back(aggregate_condition(i, AddressOf vs_intersect_aggregate))
            Else
                [as].push_back(aggregate_condition(i, AddressOf all_result_success_aggregate))
            End If

            If insert_key_mapping_commands.has(i) Then
                ks.push_back(update_key_mapping_condition(i, AddressOf insert_key_mapping))
            ElseIf erase_key_mapping_commands.has(i) Then
                ks.push_back(update_key_mapping_condition(i, AddressOf erase_key_mapping))
            ElseIf success_insert_failed_erase_key_mapping_commands.has(i) Then
                ks.push_back(update_key_mapping_condition(i, AddressOf success_insert_failed_erase_key_mapping))
            ElseIf replace_key_mapping_commands.has(i) Then
                ks.push_back(update_key_mapping_condition(i, AddressOf replace_key_mapping))
            ElseIf clear_key_mapping_commands.has(i) Then
                ks.push_back(update_key_mapping_condition(i, AddressOf clear_key_mapping))
            ElseIf i64_0_clear_key_mapping_commands.has(i) Then
                ks.push_back(update_key_mapping_condition(i, AddressOf i64_0_clear_key_mapping))
            Else
                ks.push_back(update_key_mapping_condition(i,
                                                          Sub(ByRef arg)
                                                          End Sub))
            End If
        Next

        distributors = New storageJob_distribute_switcher(+ds)
        aggregators = New storageJob_aggregate_switcher(+[as])
        update_key_mappings = New update_key_mappings_switcher(+ks)
    End Sub

    Private Function update_key_mapping(ByVal targetJobs() As indexedJob,
                                        ByVal queue_indexes() As UInt32) As Boolean
        assert(Not targetJobs Is Nothing)
        assert(Not queue_indexes Is Nothing)
        assert(targetJobs.Length() > 0)
        assert(targetJobs.Length() = queue_indexes.Length())
        For i As Int64 = 0 To targetJobs.Length() - 1
            assert(update_key_mappings.execute(storageJob(targetJobs(i)).command,
                                               New pair(Of indexedJob, UInt32)() _
                                                   With {.first = targetJobs(i), .second = queue_indexes(i)}) = 0)
        Next
        Return True
    End Function

    Protected Overrides Function aggregate(ByVal targetJobs() As indexedJob,
                                           ByVal jobqueues() As jobqueue,
                                           ByVal queue_indexes() As UInt32,
                                           ByVal inputJob As ijob) As Boolean
        Return update_key_mapping(targetJobs, queue_indexes) And aggregators.execute(targetJobs, inputJob)
    End Function

    Protected Overrides Function distribute(ByVal inputJob As ijob,
                                            ByVal targetJobs As vector(Of pair(Of UInt32, ijob)),
                                            ByRef waitall As Boolean) As Boolean
        If valid(inputJob) Then
            waitall = True
            Return distributors.execute(inputJob, targetJobs)
        Else
            Return False
        End If
    End Function

    Private Shared Shadows Function initial(ByVal name As String,
                                            ByVal config As configParser,
                                            ByVal i As storageJobRandomDistributor) As Boolean
        If distributor.initial(name, config, i) Then
            Const default_update_interval_ms As Int64 = 30000
            Dim update_interval_ms As Int64 = 0
            update_interval_ms = config.parameter(name, "key_mapping_update_interval_ms", default_update_interval_ms)
            If update_interval_ms <= 0 Then
                update_interval_ms = default_update_interval_ms
            End If
            i.initial_key_mappings(update_interval_ms)
            Return True
        Else
            Return False
        End If
    End Function

    Public Shared Shadows Function initial(ByRef name As String,
                                           ByRef config As configParser,
                                           ByRef i As Object) As Boolean
        Return initial(name, config, convertor.cast(Of storageJobRandomDistributor)(i))
    End Function
End Class
